package main

import (
	"fmt"
)

//数组是具有固定长度而且拥有零个或者多个相同或相同数据类型元素的序列。由于数组长度固定，所以在Go语言比较少直接使用。
// 而slice长度可增可减，使用场合比较多。更深入的区别在于：数组在使用的过程中都是值传递，
// 将一个数组赋值给一个新变量或作为方法参数传递时，是将源数组在内存中完全复制了一份，而不是引用源数组在内存中的地址。
// 为了满足内存空间的复用和数组元素的值的一致性的应用需求，slice出现了，每个slice都是都源数组在内存中的地址的一个引用，
// 源数组可以衍生出多个slice，slice也可以继续衍生其他slice。

//数组是值类型，长度不可伸缩；而slice 是引用类型，长度可动态增长。


//slice表示一个拥有相同类型元素的可变长度序列。slice通常被写为[]T，其中元素的类型都是T；它看上去就像没有长度的数组类型。
//数组和slice其实是紧密关联的。slice 可以看成是一种轻量级的数据结构，可以用来访问数组的部分或者全部元素，
// 而这个数组称之为 slice 的底层数组。slice 有三个属性：指针，长度和容量。指针指向数组的第一个可以从 slice 中访问的元素，
// 这个元素不一定是数组的第一个元素。长度指的是 slice 中的元素个数，不能超过 slice 的容量。
// 指针通常是从指向数组的第一个可以从 slice 中访问的元素，这个元素不一定是数组的第一个元素。
// 长度指的是 slice 中的元素个数，它不能超过 slice 的容量。容量的大小通常大于等于长度，会随着元素个数增多而动态变化。
// Go语言的内置函数 len 和 cap 用来返回 slice 的长度和容量。


func SliceTest(){
	//slice 初始化依赖于数组
	s1 := []int{12,34,56} //注意与数组初始化的区别，在内存中构建一个包括有3个元素的数组，然后将这个数组的应用赋值给s1这个slice
	a := [5]int{11,22,33,44} //定义一个长度为5的数组   最后一个元素为0
	fmt.Println(s1,len(s1),cap(s1))
	fmt.Println(a,len(a),cap(a))
	fmt.Println()

	s1 = append(s1,67)  //向slice中添加元素
	//a = append(a, 23)
	fmt.Println(s1,len(s1),cap(s1))
	fmt.Println(a,len(a),cap(a))

	s2 := a[2:4] //从数组中切片构建slice
	s3 := make([]int,10,20) //make函数初化,len=10,cap=20
	fmt.Println(s2,len(s2),cap(s2))
	fmt.Println(s3,len(s3),cap(s3))
	//s1、s2、s3都是slice
}


//内置函数len 和 cap 用来返回slice的长度和容量。在追加元素时，如果容量cap不足时，cap**一般**变为原来的2倍来实现扩容。
//cap扩容规则：
//- 如果新的cap大小是当前cap的2倍以上，则直接扩容为这个新的cap；
//- 否则循环以下操作：如果当前cap小于1024，按每次2倍增长，否则每次按当前大小1/4增长。直到增长的大小超过或等于新的cap。

//合并两个slice的全部元素到一个新的slice，并返回新slice的长度len和容量cap
func slice_add(slice1[]int, slice2[]int)(int,int){
	new_slice := append(slice1, slice2...)
	fmt.Println(new_slice,len(new_slice))
	return len(new_slice),cap(new_slice)
}
func SliceTest2(){
	//s1 := make([]int{})  //错误的定义方式
	s1 := make([]int, 5)
	s2 := make([]int, 5, 6)
	fmt.Println(s1,len(s1))
	fmt.Println(s2,len(s2))
	s1 = append(s1)
	s2 = append(s2)
	fmt.Println(s1,len(s1))
	fmt.Println(s2,len(s2))
	//追加元素
	s1 = append(s1,22,33,44,55)
	s2 = append(s2,66,77,88,99)
	fmt.Println(s1,len(s1))
	fmt.Println(s2,len(s2))
	//拼接两个slice
	lens,caps := slice_add(s1,s2)
	fmt.Println(lens,caps)
}



//作为函数参数
func SliceTest3(){
	a := []int{11,22,33,44,55}
	var b = a[0:3]
	var c = [...]int{3,6,9,2,6,4}
	d := c[0:2]
	sliceInfo(b)
	fmt.Printf("sum = %d\n",sums(b))
	fmt.Printf("sum = %d\n",sums(d))
}
func sums(a []int)int{
	s := 0
	for _,value := range a{
		s += value
	}
	return s
}
func sliceInfo(x[]int){
	fmt.Printf("len:%d, cap:%d, slice is %v\n",len(x),cap(x),x)
}



//slice 和map ，func一样，不支持 ==操作符，就是不能直接比较，唯一合法的就是和nil作比较。开发中经常会遇到需要比较两个
// slice包含的元素是否完全相等的情况，这个时候只能遍历两个slice中的所有元素 ，看它们是否完全相等。
func main() {
	//SliceTest()
	//SliceTest2()
	SliceTest3()
}